package eyer.jvm;

import java.lang.management.ManagementFactory;

import com.sun.management.OperatingSystemMXBean;

import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.math.BigDecimal;
import java.math.MathContext;

public class JVMThread implements JVMThreadMBean {
    private volatile long lastCPUTime;
    private volatile long lastCPUUpTime;
    private OperatingSystemMXBean operatingSystem;
    private RuntimeMXBean runtimeMXBean;
    private static JVMThread instance = new JVMThread();
    private ThreadMXBean threadMXBean;

    public static JVMThread getInstance() {
        return instance;
    }

    private JVMThread() {
        this.threadMXBean = ManagementFactory.getThreadMXBean();
        this.operatingSystem = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        this.runtimeMXBean = ManagementFactory.getRuntimeMXBean();

        try {
            this.lastCPUTime = this.operatingSystem.getProcessCpuTime();
        } catch (Exception e) {
        }
    }

    public BigDecimal getProcessCpuTimeRate() {
        long cpuTime = this.operatingSystem.getProcessCpuTime();
        long upTime = this.runtimeMXBean.getUptime();

        long elapsedCpu = cpuTime - this.lastCPUTime;
        long elapsedTime = upTime - this.lastCPUUpTime;

        this.lastCPUTime = cpuTime;
        this.lastCPUUpTime = upTime;
        if (elapsedTime <= 0L) {
            return new BigDecimal(0);
        }
        float cpuUsage = (float) elapsedCpu / ((float) elapsedTime * 10000.0F);
        BigDecimal cpuRate = new BigDecimal(cpuUsage, new MathContext(4));

        return cpuRate;
    }

    public int getDaemonThreadCount() {
        return this.threadMXBean.getDaemonThreadCount();
    }

    public int getThreadCount() {
        return this.threadMXBean.getThreadCount();
    }

    public long getTotalStartedThreadCount() {
        return this.threadMXBean.getTotalStartedThreadCount();
    }

    public int getDeadLockedThreadCount() {
        try {
            long[] deadLockedThreadIds = this.threadMXBean.findDeadlockedThreads();
            if (deadLockedThreadIds == null) {
                return 0;
            }
            return deadLockedThreadIds.length;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
}
